﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Windows.Forms;
using System.Drawing;

namespace Plugin
{
    public class PluginLoadedEventArgs : EventArgs
    {
        private List<Plugin> _listPlugins = null;

        public List<Plugin> Plugins
        {
            get { return _listPlugins;}
        }

        public PluginLoadedEventArgs(List<Plugin> plugins)
        {
            _listPlugins = plugins;
        }
    }

    public class PluginManager
    {
        public delegate void LoadedHandler(object sender, PluginLoadedEventArgs args);

        public event LoadedHandler Loaded = null;

        public void OnLoaded()
        {
            if (Loaded != null)
            {
                Loaded(this, new PluginLoadedEventArgs(_listPlugins));
            }
        }

        private List<Plugin> _listPlugins = new List<Plugin>();

        public List<Plugin> Plugins
        {
            get { return _listPlugins; }
        }

        public PluginManager()
        {
            
        }

        public void InitializePlugins()
        {
            string searchPath = string.Format("{0}\\Plugins", Application.StartupPath);
            string[] files = Directory.GetFiles(searchPath, "*.dll");

            foreach (string file in files)
            {
                LoadTypes(file);
            }

            OnLoaded();
        }

        private void LoadTypes(string file)
        {
            try
            {
                // TCC: This method is retarded - Need to determine how to load
                // plugins using Assembly.Load so duplicate assemblies are never loaded
                Assembly asm = Assembly.LoadFrom(file);

                foreach (Type asmType in asm.GetTypes())
                {
                    foreach (object attr in asmType.GetCustomAttributes(false))
                    {
                        if (attr is ClassAttribute)
                        {
                            ClassAttribute ccattr = attr as ClassAttribute;
                            Plugin plugin = new Plugin(asmType, asm, ccattr);

                            //TCC: Find the events in the plugin class
                            foreach (EventInfo einfo in asmType.GetEvents())
                            {
                                foreach (object eattr in einfo.GetCustomAttributes(false))
                                {
                                    if (eattr is EventAttribute)
                                    {
                                        EventAttribute ceattr = eattr as EventAttribute;

                                        plugin.EventAttributes.Add(ceattr);
                                    }
                                }
                            }

                            //TCC: Find the methods in the plugin class
                            foreach (MethodInfo minfo in asmType.GetMethods())
                            {
                                foreach (object mattr in minfo.GetCustomAttributes(false))
                                {
                                    if (mattr is MethodAttribute)
                                    {
                                        MethodAttribute cmattr = mattr as MethodAttribute;

                                        plugin.MethodAttributes.Add(cmattr);
                                    }
                                }
                            }


                            //TCC: Find the fields in the plugin class
                            foreach (FieldInfo finfo in asmType.GetFields())
                            {
                                foreach (object fattr in finfo.GetCustomAttributes(false))
                                {
                                    if (fattr is FieldAttribute)
                                    {
                                        FieldAttribute cfattr = fattr as FieldAttribute;

                                        plugin.FieldAttributes.Add(cfattr);
                                    }
                                }
                            }
                            _listPlugins.Add(plugin);
                        }
                    }
                }
            }
            catch (System.Exception x)
            {
                int asdf = 55;
            }
        }
    }
}
